/* DESCR.H
 * OPENMV debugger include 
 * Copyright (c) 2007 MissingNODE 
 * Based on GPL OpenQM Code
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * 
 * 
 * START-HISTORY:
 * Oct-10-2007 Initial Revision
 * END-HISTORY
 *
 * START-DESCRIPTION:
 *
 * Every variable is represented by a DESCRIPTOR structure.  In some cases
 * this holds all the data associated with the variable.  In other cases it
 * contains pointers to other structures.
 *
 * UNASSIGNED   All local variable start out in this state.
 *
 * ADDR         A pointer to another descriptor.
 *
 * INTEGER      A 32 bit integer value.
 *
 * FLOATNUM     A floating point number.
 *
 * SUBR         A pointer to a memory resident TMBasic program.
 *              Created by CALL transforming a character string holding the
 *              name of the subroutine.  This string is still available via
 *              a pointer in the descriptor.
 *
 * STRING       A character string.
 *              Strings are stored as a series of STRING_CHUNK structures. By
 *              holding strings in this way, some operations such as
 *              concatenation are much faster than using contiguous strings.
 *              Conversely, some operations are slower.
 *              The actual string represented by the string chunks may be
 *              referenced by more than one descriptor. This is controlled
 *              using a reference count in the first chunk.
 *
 * FILE_REF     A file variable.
 *              Points to a FILE_VAR structure.  This includes a reference
 *              count to allow multiple descriptors to share a FILE_VAR.
 *
 * ARRAY        An array.
 *              Points to an ARRAY_HEADER structure.  Again, this has a
 *              reference count.  The array header contains information about
 *              the array dimensions and points to a list of ARRAY_CHUNK
 *              structures.  This two level approach significantly improves
 *              performance of redimensioning arrays.
 *
 * COMMON       A common block.
 *              Common blocks are actually held as arrays, each element of
 *              which is an entry from the common declaration, perhaps also an
 *              array.  The common blocks are chained together through the
 *              next_common item in the array header. Element 0 of the common
 *              "array" is the name of the block, the remaining elements are
 *              the common itself. The chain has its head in named_common. The
 *              blank common is addressed by blank_common.
 *
 * IMAGE        A screen image.
 *              Points to a SCREEN_IMAGE structure.  On a Windows TMConsole
 *              session, this structure contains the actual screen data. On a
 *              TMTerm session, the data is held locally by TMTerm and a
 *              unique reference id is stored in the SCREEN_IMAGE.
 *             
 * BTREE        A binary tree data item.
 *              Not accessible to user mode programs (because it's a bit
 *              awkward to use), these are used internally by the TMBasic
 *              compiler and the query processor for fast access tables.
 *
 * SELLIST      A select list variable.
 *              Used by TMBasic operations that work with select list
 *              variables as distinct from numbered select lists.  Because this
 *              variable type was introduced late in the life of QM, the
 *              numbered lists are handled differently.
 *
 * PMATRIX      Pick style systems use a different form of matrix than 
 *              Information style systems. Firstly, Pick matrices have no zero
 *              element. Secondly, a Pick matrix in a common block is just a
 *              list of simple data items. Both styles have their advantages
 *              and disadvantages. TextMark supports both, though the Information
 *              style is the default. The PMATRIX descriptor defines a Pick
 *              style matrix in a common block.
 *
 * SOCK         Socket.
 *
 * LOCALVARS    A local variable pool.
 *              Local variables are held as arrays in exactly the same way as
 *              common. As far as the program using them is concerned, they
 *              are common variables.
 *              To allow for recursion, entry to an internal subroutine that
 *              declares local variables will stack any previous incarnation
 *              of the local variable pool by chaining it on to the next_common
 *              item in the array header.
 *
 * OBJ          Object.
 *
 * OBJCD        Object code pointer for property access.
 *
 * OBJCDX       Undefined object routine reference (variant on OBJCD)
 *
 * PERSISTENT   Persistent public and private variables of a CLASS module.
 *              For most purposes, this is the same as a COMMON block. The
 *              most significant difference is that element 0 is not
 *              reserved for the block name but is available for normal use.
 *
 * END-DESCRIPTION
 *
 * START-CODE
 */
struct DESCRIPTOR {
                   u_char type;               /* Item type */
                   u_char flags;
#ifdef BIG_ENDIAN_SYSTEM
   #define InitDescr(d, t) *((short int *)d) = ((t) << 8)
#else
   #define InitDescr(d, t) *((short int *)d) = t
#endif
                   short int n1;               /* Used by OBJCDX */
                   union {
                          /* ADDR */
                          DESCRIPTOR * d_addr; /* Ptr to descriptor (ADDR) */

                          /* INTEGER */
                          long int value;      /* Value */

                          /* FLOATNUM */
                          double float_value;  /* Value */

                          /* SUBR */
                          struct {
                                  void * object;
                                  STRING_CHUNK * saddr;
                                 } subr;

                          /* STRING, SELLIST */
                          struct {
                                  STRING_CHUNK * saddr;
                                  u_char rmv_idx;    /* REMOVE pointer index */
                                 } str;

                          /* FILE_REF */
                          FILE_VAR * fvar;     /* File var */

                          /* ARRAY */
                          ARRAY_HEADER * ahdr_addr;

                          /* COMMON and PERSISTENT */
                          ARRAY_HEADER * c_addr;

                          /* IMAGE */
                          SCREEN_IMAGE * i_addr;

                          /* BTREE */
                          BTREE_HEADER * btree;

                          /* PMATRIX */
                          PMATRIX_HEADER * pmatrix;

                          /* SOCK */
                          SOCKVAR * sock;

                          /* LOCALVARS */
                          ARRAY_HEADER * lv_addr;

                          /* OBJ */
                          OBJDATA * objdata;

                          /* OBJCD */
                          struct {
                                  OBJDATA * objdata;      /* Object associated with this data */
                                  unsigned short int key; /* Key value */
                                  u_char arg_ct;          /* Arg count + var args flag */
                                 } objcode;

                          /* OBJCDX */
                          struct {
                                  OBJDATA * objdata;      /* Object associated with this data */
                                  char * undefined_name;
                                 } objundef;

                          /* Debugging */
                          struct {
                                  long int w1;
                                  long int w2;
                                 } dbg;
                         } data;
                  };

/* Descriptor types (Also in BP INT$KEYS.H) */
#define UNASSIGNED    0
#define ADDR          1
#define INTEGER       2
#define FLOATNUM      3
#define COMPLEX_DESCR 4     /* Descriptors with types greater than or equal
                               to this value have subordinate data which
                               must be handled by k_release().              */
#define SUBR          4
#define STRING        5
#define FILE_REF      6
#define ARRAY         7
#define COMMON        8
#define IMAGE         9
#define BTREE        10
#define SELLIST      11
#define PMATRIX      12
#define SOCK         13
#define LOCALVARS    14
#define OBJ          15
#define OBJCD        16
#define OBJCDX       17
#define PERSISTENT   18

/* When adding new entry, all places that include a comment containing
   ++ALLTYPES++ must be amended.                                       */
/* This list is also in BP DEBUG.H */

/* Flags */
#define DF_REUSE        0x01   /* Set by reuse function */
#define DF_REMOVE       0x02   /* Remove table entry allocated */
#define DF_ARG          0x04   /* Argument pointer */
#define DF_WATCH        0x08   /* Set by debug watch, cleared by data change */
#define DF_ARGSET       0x10   /* Set on callv arg vars, cleared by data change */
#define DF_SYSTEM       0x20   /* Set on system variables (STORSYS opcode) */
#define DF_MOVE         0x40   /* Move descr in object function/subr call */
#define DF_CHANGE       (DF_WATCH | DF_ARGSET)  /* Flags to clear on change */

/* ====================================================================== */

/* --------------- String descriptor STRING --------------- */

struct STRING_CHUNK {
        STRING_CHUNK * next;  /* Ptr to next chunk */
        short int alloc_size; /* Allocated space excluding header */
        short int bytes;      /* Actual used bytes */
        /* The following are only valid in the first chunk */
        long int string_len;  /* Total length of all chunks */
        long int field;       /* Hint field number and... */
        long int offset;      /* ...offset. In SELLIST this is item count */
        short int ref_ct;     /* Reference count */
        u_char data[1];
       };
#define STRING_CHUNK_HEADER_SIZE (offsetof(STRING_CHUNK, data))
#define MAX_STRING_CHUNK_SIZE ((signed int)(16384 - STRING_CHUNK_HEADER_SIZE))


/* ------------------ File descriptor FILE_REF ------------------ */

typedef struct SQ_FILE SQ_FILE;
struct SQ_FILE {
                OSFILE fu;           /* -ve if open to create */
                u_char * buff;       /* Buffer */
                int64 posn;          /* File: File position
                                        Port: Offset into buffer */
                int64 line;          /* Current line no */
                int64 base;          /* Base address of block */
                char * record_name;  /* Record id */
                short int record_name_len;
                short int bytes;     /* Bytes in buffer */
                char * pathname;     /* File pathname */
                long int timeout;    /* Timeout, -ve if none */
                unsigned short int flags;
#define SQ_NOBUF  0x0001             /* Unbuffered */
#define SQ_DIRTY  0x0002             /* Buffer needs writing */
#define SQ_PORT   0x0004             /* Is a port */
#define SQ_CHDEV  0x0008             /* Character mode device */
#define SQ_FIFO   0x0010             /* FIFO */
#define SQ_NOTFL  0x001C             /* Mask for "files" that aren't files */
               };

/* File variable structure
   See !!FVAR_CREATE!! and !!FVAR_DESTROY!! */
struct FILE_VAR {
                 short int ref_ct;       /* Reference count */
                 short int file_id;      /* File table index */
                 long int index;         /* Sequential reference counter */
                 u_char type;
/* !!FVAR_TYPES!! */
#define INITIAL_FVAR    0
#define DIRECTORY_FILE  1
#define DYNAMIC_FILE    2
#define SEQ_FILE        3
#define NET_FILE        4
#define VFS_FILE        5
/* Tokens also in BP DEBUG.H */
                 u_char flags;
#define FV_RDONLY       0x01             /* Read only file */
#define FV_NON_TXN      0x02             /* Updates are non-transactional */
                 short int id_len;       /* Length of id and... */
                 u_char * id;            /* ...actual id of last record read */
                 u_char * voc_name;
               
                 union {
                        struct {
                                DH_FILE * dh_file;   /* DH_FILE structure */
                                AK_CTRL * ak_ctrl;   /* AK control data */
                               } dh;
                        struct {
                                SQ_FILE * sq_file;   /* SQ_FILE structure */
                               } seq;
                        struct {
                                unsigned short int mark_mapping : 1;
                               } dir;
                        struct {
                                int file_no;
                                short int host_index;
                               } net;
                       } access;
       };


/* ------------------ Array descriptor ARRAY ------------------ */

#define MAX_ARRAY_CHUNK_SIZE 200  /* Max elements in a single chunk */

struct ARRAY_CHUNK {
        short int num_descr;
        short int pad;
        DESCRIPTOR descr[1];
       };

struct ARRAY_HEADER {
        short int ref_ct;
        unsigned short int flags;
          /* These tokens are also in BP INT$KEYS.H */
          #define AH_PICK_STYLE  0x0001  /* Pick style matrix */
          #define AH_AUTO_DELETE 0x0002  /* Self-deleting common block */
        long int rows;
        long int cols;              /* Zero if one dimension */
        long int alloc_elements;    /* Allocated descriptors and... */
        long int used_elements;     /* ...number actually used (could have
                                       redimensioned to smaller size) */
        ARRAY_HEADER * next_common; /* Chain linking named common */
        short int num_chunks;       /* Entries in chunk array below. There may
                                       be unused entries at the end of the
                                       array which will be set to NULL.      */
        short int pad;
        ARRAY_CHUNK * chunk[1];
       };

/* Macro to find an array element given its header and element offset */
#define Element(hdr,n) \
   (&(hdr->chunk[(n) / MAX_ARRAY_CHUNK_SIZE]->descr[(n) % MAX_ARRAY_CHUNK_SIZE]))

/* ------------------ Screen image IMAGE ------------------ */

struct SCREEN_IMAGE {
                     short int ref_ct;
                     short int pad;
                     void * buffer;        /* Screen image data */
                     short int x;          /* Left edge of block */
                     short int y;          /* Top edge of block */
                     short int w;          /* Width of block */
                     short int h;          /* Height of block */
                     short int line;       /* Cursor line position */
                     short int col;        /* Cursor column position */
                     short int pagination;
                     short int attr;       /* ms8 = Inverse, ls8 = attr */
                     long int id;
                    };

/* ------------------ Binary Tree BTREE ------------------ */

typedef struct BTREE_ELEMENT BTREE_ELEMENT;
struct BTREE_ELEMENT {
                      BTREE_ELEMENT * parent;
                      BTREE_ELEMENT * left;
                      BTREE_ELEMENT * right;
                      u_char * data;
                      u_char * key[1];
                     };

struct BTREE_HEADER {
                     short int ref_ct;
                     short int pad;
                     BTREE_ELEMENT * head;
                     BTREE_ELEMENT * current;
                     u_char keys;
                     u_char flags[1];
/* Additive flags values: */
#define BT_RIGHT_ALIGNED 0x01
#define BT_DESCENDING    0x02
#define BT_UNIQUE        0x04
#define BT_DATA          0x08      /* Has data element */
                    };

/* ---------------------- PMATRIX ------------------------ */

struct PMATRIX_HEADER
 {
  DESCRIPTOR * com_descr;         /* Associated COMMON */
  unsigned short int base_offset; /* Where is element 1 */
  unsigned short int rows;
  unsigned short int cols;        /* Zero if one dimension */
 };

/* ------------------------ SOCK ------------------------- */

struct SOCKVAR
{
 int ref_ct;
 int socket_handle;
 int port;                   /* Port number */
 unsigned short int flags;
    #define SKT_BLOCKING       0x0001 /* Blocking mode */
    #define SKT_NON_BLOCKING   0x0002 /* Non-blocking (Irrelevant here) */
    #define SKT_SERVER         0x0004 /* Opened with CREATE.SERVER.SOCKET */
    #define SKT_INCOMING       0x0008 /* Opened with ACCEPT.SOCKET.CONNECTION */
    #define SKT_USER_MASK      0x0001 /* Flags settable by user */
 char ip_addr[15+1];         /* IP address */
};

/* -------------------- OBJECT NAME MAP ------------------ */

typedef struct OBJECT_NAME_MAP OBJECT_NAME_MAP;
struct OBJECT_NAME_MAP  /* This is embedded in the object code */
{
 /* Multi-byte items are always low byte first because the object stream
    is machine architecture independent                                  */
 u_char next;          /* Offset of next entry, zero in last entry */
 u_char lo_var;        /* Public var no, ls 8 bits */
 u_char hi_var;        /* Public var no, ms 8 bits */
 u_char lo_set;        /* SET routine / method subroutine key, ls 8 bits */
 u_char hi_set;        /* SET routine / method subroutine key, ms 8 bits */
 u_char lo_get;        /* GET routine / method subroutine key, ls 8 bits */
 u_char hi_get;        /* GET routine / method function key, ms 8 bits */
 u_char set_arg_ct;    /* SET routine / method subroutine arg count */
 u_char get_arg_ct;    /* GET routine / method function arg count */
 char name[1];         /* Item name, upper case, null terminated */
};
/* Note: the two arg count items use the top bit to indicate that the
   routine is declared as VAR.ARGS.                                   */

#define SetKey(p) ((p)->lo_set + ((short int)((p)->hi_set) << 8))
#define GetKey(p) ((p)->lo_get + ((short int)((p)->hi_get) << 8))
#define PublicVar(p) ((p)->lo_var + ((short int)((p)->hi_var) << 8))
#define NextNameMapEntry(p) (((p)->next == 0)?NULL:((OBJECT_NAME_MAP *)( ((char *)(p)) + ((p)->next))))

/* ----------------------- OBJUNDEF ---------------------- */

struct OBJUNDEF   /* An undefined object handler reference */
{
 int ref_ct;
 OBJDATA * objdata;      /* Object associated with this data */
 char * undefined_name;  /* The handler name we could not find */
 unsigned short int key; /* Key value */
};

/* ------------------------- OBJ -------------------------

   Object A inherits B and C
   B inherits D
   C inherits E

   -----   -----   -----        In this diagram, the link to the right
   | A |---| B |---| D |        is the "inherits" pointer and the link
   -----   -----   -----        below is the "next_inherited" pointer.
             |
           -----   -----
           | C |---| E |
           -----   -----
*/

struct OBJDATA    /* The object itself */
{
 int ref_ct;                 /* Reference count */
 void * objprog;             /* Object program pointer */
 OBJECT_NAME_MAP * name_map; /* Start of name map */
 ARRAY_HEADER * obj_vars;    /* PUBLIC and GLOBAL data array */
 OBJDATA * inherits;         /* Head of inherited objects list */
 OBJDATA * next_inherited;   /* Links further items in inheritance chain */
 bool destructor_run;        /* Set on calling destructor to avoid loops */
};

/* ====================================================================== */

#define Release(d) if ((d)->type >= COMPLEX_DESCR) k_release(d)
#define IncrRefCt(d) if ((d)->type >= COMPLEX_DESCR) k_incr_refct(d)

#define GetBool(d) if ((d)->type != INTEGER) k_get_bool(d)
#define GetInt(d) if ((d)->type != INTEGER) k_get_int(d)
#define GetNum(d) if (((d)->type != INTEGER) && ((d)->type != FLOATNUM)) k_get_num(d)
#define GetString(d) if ((d)->type != STRING) k_get_string(d)
